home *** CD-ROM | disk | FTP | other *** search
/ Suzy B Software 2 / Suzy B Software CD-ROM 2 (1994).iso / new_file / mintprgs / mint112s / mint112s.lzh / bios.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-30  |  30.8 KB  |  1,308 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992,1993,1994 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. /*
  8.  * BIOS replacement routines
  9.  */
  10.  
  11. #include "mint.h"
  12. #include "xbra.h"
  13.  
  14. #define UNDEF 0        /* should match definition in tty.c */
  15.  
  16. /* some key definitions */
  17. #define CTRLALT 0xc
  18. #define DEL 0x53    /* scan code of delete key */
  19. #define UNDO 0x61    /* scan code of undo key */
  20.  
  21. /* BIOS device definitions */
  22. #define CONSDEV 2
  23. #define AUXDEV 1
  24. #define PRNDEV 0
  25. #define    SERDEV 6    /* First serial port */
  26.  
  27. /* BIOS devices 0..MAX_BHANDLE-1 can be redirected to GEMDOS files */
  28. #define MAX_BHANDLE    4
  29.  
  30. /* BIOS redirection maps */
  31. const short binput[MAX_BHANDLE] = { -3, -2, -1, -4 };
  32. const short boutput[MAX_BHANDLE] = { -3, -2, -1, -5 };
  33.  
  34. /* tty structures for the BIOS devices -- see biosfs.c */
  35. extern struct tty con_tty, aux_tty, midi_tty, sccb_tty, scca_tty, ttmfp_tty;
  36. extern struct bios_tty bttys[], midi_btty;
  37. extern short btty_max;
  38.  
  39. extern int tosvers;    /* from main.c */
  40.  
  41. char *kbshft;        /* set in main.c */
  42.  
  43. short console_in;    /* wait condition for console input */
  44.  
  45. /* save cluster sizes of BIOS drives 0..31 (used in tosfs.c) */
  46. unsigned short clsizb[32];
  47.  
  48. /* some BIOS vectors; note that the routines at these vectors may do nasty
  49.  * things to registers!
  50.  */
  51.  
  52. #define RWABS *((long *)0x476L)
  53. #define MEDIACH *((long *)0x47eL)
  54. #define GETBPB *((long *)0x472L)
  55.  
  56.  
  57. /* these are supposed to be tables holding the addresses of the
  58.  * first 8 BconXXX functions, but in fact only the first 5 are
  59.  * placed here (and device 5 only has Bconout implemented; 
  60.  * we don't use that device (raw console) anyway).
  61.  */
  62.  
  63. #define xconstat ((long *)0x51eL)
  64. #define xconin     ((long *)0x53eL)
  65. #define xcostat ((long *)0x55eL)
  66. #define xconout    ((long *)0x57eL)
  67.  
  68. #if 1
  69. /* if the system has Bconmap the ones >= 6 are in a table available
  70.  * thru Bconmap(-2)...
  71.  */
  72. #define MAPTAB (bconmap2->maptab)
  73.  
  74. /* and then do BCOSTAT ourselves, the BIOS SCC ones are often broken */
  75. #define BCOSTAT(dev) \
  76.     (((unsigned)dev <= 4) ? ((tosvers >= 0x0102) ? \
  77.        (int)callout1(xcostat[dev], dev) : Bcostat(dev)) : \
  78.        ((has_bconmap && (unsigned)dev-SERDEV < btty_max) ? \
  79.         bcxstat(MAPTAB[dev-SERDEV].iorec+1) : Bcostat(dev)))
  80. #define BCONOUT(dev, c) \
  81.     (((unsigned)dev <= 4) ? ((tosvers >= 0x0102) ? \
  82.        callout2(xconout[dev], dev, c) : Bconout(dev, c)) : \
  83.        ((has_bconmap && (unsigned)dev-SERDEV < btty_max) ? \
  84.         callout2(MAPTAB[dev-SERDEV].bconout, dev, c) : Bconout(dev, c)))
  85. #define BCONSTAT(dev) \
  86.     (((unsigned)dev <= 4) ? ((tosvers >= 0x0102) ? \
  87.        (int)callout1(xconstat[dev], dev) : Bconstat(dev)) : \
  88.        ((has_bconmap && (unsigned)dev-SERDEV < btty_max) ? \
  89.         (int)callout1(MAPTAB[dev-SERDEV].bconstat, dev) : Bconstat(dev)))
  90. #define BCONIN(dev) \
  91.     (((unsigned)dev <= 4) ? ((tosvers >= 0x0102) ? \
  92.        callout1(xconin[dev], dev) : Bconin(dev)) : \
  93.        ((has_bconmap && (unsigned)dev-SERDEV < btty_max) ? \
  94.         callout1(MAPTAB[dev-SERDEV].bconin, dev) : Bconin(dev)))
  95. #else
  96. #define BCOSTAT(dev) \
  97.     ((tosvers > 0x0102 && (unsigned)dev <= 4) ? \
  98.        (int)callout1(xcostat[dev], dev) : Bcostat(dev))
  99. #define BCONOUT(dev, c) \
  100.     ((tosvers > 0x0102 && (unsigned)dev <= 4) ? \
  101.        callout2(xconout[dev], dev, c) : Bconout(dev, c))
  102. #define BCONSTAT(dev) \
  103.     ((tosvers > 0x0102 && (unsigned)dev <= 4) ? \
  104.        (int)callout1(xconstat[dev], dev) : Bconstat(dev))
  105. #define BCONIN(dev) \
  106.     ((tosvers > 0x0102 && (unsigned)dev <= 4) ? \
  107.        callout1(xconin[dev], dev) : Bconin(dev))
  108. #endif
  109.  
  110. /* variables for monitoring the keyboard */
  111. IOREC_T    *keyrec;        /* keyboard i/o record pointer */
  112. BCONMAP2_T *bconmap2;        /* bconmap struct */
  113. short    kintr = 0;        /* keyboard interrupt pending (see intr.s) */
  114.  
  115. /* replacement *costat for BCOSTAT above */
  116. INLINE static int bcxstat (IOREC_T *wrec)
  117. {
  118.     unsigned s = wrec->head - wrec->tail;
  119.     if ((int)s <= 0)
  120.         s += wrec->buflen;
  121.     return s < 3 ? 0 : -1;
  122. }
  123.  
  124. /* Getmpb is not allowed under MiNT */
  125.  
  126. long ARGS_ON_STACK
  127. getmpb(ptr)
  128.     void *ptr;
  129. {
  130.     UNUSED(ptr);
  131.  
  132.     DEBUG(("failed call to Getmpb"));
  133.     return -1;
  134. }
  135.  
  136. INLINE static int
  137. isonline(b)
  138.     struct bios_tty *b;
  139. {
  140.     if (b->tty == &aux_tty) {
  141.     /* modem1 */
  142.     /* CD is !bit 1 on the 68901 GPIP port */
  143.         return (1 << 1) & ~*((volatile char *) 0xfffffa01L);
  144.     } else if (b->tty == &sccb_tty) {
  145.     /* modem2 */
  146.     /* CD is bit 3 of read register 0 on SCC port B */
  147.         short sr = spl7();
  148.         unsigned char r;
  149.         volatile char dummy;
  150.         dummy = *((volatile char *) 0xfffffa01L);
  151.         r = (1 << 3) & *((volatile char *) 0xffff8c85L);
  152.         spl(sr);
  153.         return r;
  154.     } else if (b->tty == &scca_tty) {
  155.     /* serial2 */
  156.     /* like modem2, only port A */
  157.         short sr = spl7();
  158.         unsigned char r;
  159.         volatile char dummy;
  160.         dummy = *((volatile char *) 0xfffffa01L);
  161.         r = (1 << 3) & *((volatile char *) 0xffff8c81L);
  162.         spl(sr);
  163.         return r;
  164.     } else {
  165.     /* unknown port, assume CD always on. */
  166.         return 1;
  167.     }
  168. }
  169.  
  170. INLINE static int
  171. isbrk(b)
  172.     struct bios_tty *b;
  173. {
  174.     if (b->tty == &aux_tty) {
  175.     /* modem1 */
  176.     /* break is bit 3 in the 68901 RSR */
  177.         return (1 << 3) & *((volatile char *) 0xfffffa2bL);
  178.     } else if (b->tty == &sccb_tty) {
  179.     /* modem2 */
  180.     /* break is bit 7 of read register 0 on SCC port B */
  181.         short sr = spl7();
  182.         unsigned char r;
  183.         volatile char dummy;
  184.         dummy = *((volatile char *) 0xfffffa01L);
  185.         r = (1 << 7) & *((volatile char *) 0xffff8c85L);
  186.         spl(sr);
  187.         return r;
  188.     } else if (b->tty == &scca_tty) {
  189.     /* serial2 */
  190.     /* like modem2, only port A */
  191.         short sr = spl7();
  192.         unsigned char r;
  193.         volatile char dummy;
  194.         dummy = *((volatile char *) 0xfffffa01L);
  195.         r = (1 << 7) & *((volatile char *) 0xffff8c81L);
  196.         spl(sr);
  197.         return r;
  198.     } else if (b->tty == &ttmfp_tty) {
  199.     /* serial1 */
  200.         return (1 << 3) & *((volatile char *) 0xfffffaabL);
  201.     } else {
  202.     /* unknown port, cannot detect breaks... */
  203.         return 0;
  204.     }
  205. }
  206.  
  207. INLINE unsigned
  208. ionwrite(wrec)
  209.     IOREC_T *wrec;
  210. {
  211.     unsigned s = wrec->head - wrec->tail;
  212.     if ((int)s <= 0)
  213.         s += wrec->buflen;
  214.     if ((int)(s -= 2) < 0)
  215.         s = 0;
  216.     return s;
  217. }
  218.  
  219. INLINE unsigned
  220. ionread(irec)
  221.     IOREC_T *irec;
  222. {
  223.     unsigned r = irec->tail - irec->head;
  224.     if ((int)r < 0)
  225.         r += irec->buflen;
  226.     return r;
  227. }
  228.  
  229. INLINE unsigned
  230. btty_ionread(b)
  231.     struct bios_tty *b;
  232. {
  233.     long ret = 0;
  234. #if 1
  235. /* try trap #1 first, to read hardware fifos too...
  236.  * (except for modem1/serial1 which are always in one-interrupt-per-byte mode)
  237.  */
  238.     if (b != bttys && b->tty != &ttmfp_tty &&
  239.         !rsvf_ioctl (b->tosfd, &ret, FIONREAD))
  240.         return ret;
  241. #endif
  242.     return ionread (b->irec);
  243. }
  244.  
  245. #define _hz_200 (*((long *)0x4baL))
  246.  
  247. INLINE static void
  248. checkbtty(b, sig)
  249.     struct bios_tty *b;
  250.     int sig;
  251. {
  252.     long *l;
  253.  
  254.     if (!b->irec)
  255.         return;
  256.     if (!b->clocal && !isonline(b)) {
  257.         b->vticks = 0;
  258.         b->bticks = _hz_200 + 0x80000000L;
  259.         if (!(b->tty->state & TS_BLIND)) {
  260. /* just lost carrier...  set TS_BLIND, let reads and writes return */
  261.             b->tty->state |= TS_BLIND;
  262.             iocsbrk (b->bdev, TIOCCBRK, b);
  263.             if (sig) {
  264.                 b->orec->tail = b->orec->head;
  265.                 DEBUG(("checkbtty: bdev %d disconnect", b->bdev));
  266.                 if (!(b->tty->sg.sg_flags & T_NOFLSH))
  267.                     iread (b->bdev, (char *) NULL, 0, 1, 0);
  268.                 if (b->tty->pgrp)
  269. /* ...and here is the long missed :) SIGHUP  */
  270.                     killgroup(b->tty->pgrp, SIGHUP, 1);
  271.             }
  272.             wake(IO_Q, (long)b);
  273.             wake(IO_Q, (long)&b->tty->state);
  274.         }
  275.         return;
  276.     }
  277.     if (b->tty->state & TS_BLIND) {
  278. /* just got carrier (or entered local mode), clear TS_BLIND and
  279.  * wake whoever waits for it */
  280.         b->tty->state &= ~(TS_BLIND|TS_HOLD);
  281.         wake(IO_Q, (long)&b->tty->state);
  282.     }
  283.     if (sig) {
  284.         if (b->brkint && isbrk(b)) {
  285.             if (!b->bticks) {
  286. /* the break should last for more than 200 ms or the equivalent of
  287.  * 48 10-bit chars at ispeed (then its probably not line noise...)
  288.  */
  289.                 if ((unsigned long)b->ispeed <= 2400)
  290.                     b->bticks = _hz_200+40L;
  291.                 else
  292.                     b->bticks = _hz_200+(480L*200L/(unsigned long)b->ispeed);
  293.                 if (!b->bticks)
  294.                     b->bticks = 1;
  295.             } else if (_hz_200 - b->bticks > 0) {
  296. /* every break only one interrupt please */
  297.                 b->bticks += 0x80000000L;
  298.                 DEBUG(("checkbtty: bdev %d break(int)", b->bdev));
  299.                 if (!(b->tty->sg.sg_flags & T_NOFLSH))
  300.                     iread (b->bdev, (char *) NULL, 0, 1, 0);
  301.                 if (b->tty->pgrp)
  302.                     killgroup(b->tty->pgrp, SIGINT, 1);
  303.             }
  304.         } else
  305.             b->bticks = 0;
  306.     }
  307.     if (!b->vticks || _hz_200 - b->vticks > 0) {
  308.         long r;
  309.  
  310.         if ((r = (long)b->tty->vmin - btty_ionread(b)) <= 0) {
  311.             b->vticks = 0;
  312.             wake(IO_Q, (long)b);
  313.             l = b->rsel;
  314.             if (*l)
  315.                 wakeselect(*l);
  316.         } else if ((--r, r *= 2000L) > (unsigned long)b->ispeed) {
  317.             b->vticks = _hz_200 + (r/(unsigned long)b->ispeed);
  318.             if (!b->vticks)
  319.                 b->vticks = 1;
  320.         } else
  321.             b->vticks = 0;
  322.     }
  323.     if (b->tty->state & TS_HOLD)
  324.         return;
  325.     l = b->wsel;
  326.     if (*l) {
  327.         short i = b->orec->tail - b->orec->head;
  328.         if (i < 0)
  329.             i += b->orec->buflen;
  330.         if (i < b->orec->hi_water)
  331.             wakeselect(*l);
  332.     }
  333. }
  334.  
  335. void
  336. checkbttys(void)
  337. {
  338.     struct bios_tty *b;
  339.  
  340.     for (b=bttys;b<bttys+btty_max;b++) {
  341.         checkbtty(b, 1);
  342.     }
  343.     b=&midi_btty;
  344.     if (!b->vticks || _hz_200 - b->vticks > 0) {
  345.         long r, *l;
  346.  
  347.         if ((r = (long)b->tty->vmin - ionread(b->irec)) <= 0) {
  348.             b->vticks = 0;
  349.             wake(IO_Q, (long)b);
  350.             l = b->rsel;
  351.             if (*l)
  352.                 wakeselect(*l);
  353.         } else if ((--r, r *= 2000L) > (unsigned long)31250) {
  354.             b->vticks = _hz_200 + (r/(unsigned long)31250);
  355.             if (!b->vticks)
  356.                 b->vticks = 1;
  357.         } else
  358.             b->vticks = 0;
  359.     }
  360. }
  361.  
  362. void
  363. checkbttys_vbl(void)
  364. {
  365.     struct bios_tty *b;
  366.  
  367.     for (b=bttys;b<bttys+btty_max;b++) {
  368.         if (!b->clocal && b->orec->tail != b->orec->head && !isonline(b))
  369.             b->orec->tail = b->orec->head;
  370.     }
  371. }
  372.  
  373. /* check 1 tty without raising sigs, needed after turning off local mode
  374.  * (to avoid getting SIGHUP'd immediately...)
  375.  */
  376.  
  377. void
  378. checkbtty_nsig(b)
  379.     struct bios_tty *b;
  380. {
  381.     checkbtty(b, 0);
  382. }
  383.  
  384. /*
  385.  * Note that BIOS handles 0 - MAX_BHANDLE now reference file handles;
  386.  * to get the physical devices, go through u:\dev\
  387.  *
  388.  * A note on translation: all of the bco[n]XXX functions have a "u"
  389.  * variant that is actually what the user calls. For example,
  390.  * ubconstat is the function that gets control after the user does
  391.  * a Bconstat. It figures out what device or file handle is
  392.  * appropriate. Typically, it will be a biosfs file handle; a
  393.  * request is sent to biosfs, and biosfs in turn figures out
  394.  * the "real" device and calls bconstat.
  395.  */
  396.  
  397. /*
  398.  * WARNING: syscall.spp assumes that ubconstat never blocks.
  399.  */
  400. long ARGS_ON_STACK
  401. ubconstat(dev)
  402. int dev;
  403. {
  404.     if (dev < MAX_BHANDLE) {
  405.         FILEPTR *f = curproc->handle[binput[dev]];
  406.         return file_instat(f) ? -1 : 0;
  407.     }
  408.     else
  409.         return bconstat(dev);
  410. }
  411.  
  412. long
  413. bconstat(dev)
  414. int dev;
  415. {
  416.     if (dev == CONSDEV) {
  417.         if (checkkeys()) return 0;
  418.         return (keyrec->head != keyrec->tail) ? -1 : 0;
  419.     }
  420.     if (dev == AUXDEV && has_bconmap)
  421.         dev = curproc->bconmap;
  422.  
  423.     return BCONSTAT(dev);
  424. }
  425.  
  426. /* bconin: input a character */
  427. /*
  428.  * WARNING: syscall.spp assumes that ubconin never
  429.  * blocks if ubconstat returns non-zero.
  430.  */
  431. long ARGS_ON_STACK
  432. ubconin(dev)
  433. int dev;
  434. {
  435.     if (dev < MAX_BHANDLE) {
  436.         FILEPTR *f = curproc->handle[binput[dev]];
  437.         return file_getchar(f, RAW);
  438.     }
  439.     else
  440.         return bconin(dev);
  441. }
  442.  
  443. long
  444. bconin(dev)
  445. int dev;
  446. {
  447.     IOREC_T *k;
  448.     long r;
  449.     short h;
  450.  
  451.     if (dev == CONSDEV) {
  452.         k = keyrec;
  453. again:
  454.         while (k->tail == k->head) {
  455.             sleep(IO_Q, (long)&console_in);
  456.         }
  457.  
  458.         if (checkkeys()) goto again;
  459.  
  460.         h = k->head + 4;
  461.         if (h >= k->buflen)
  462.             h = 0;
  463.         r = *((long *)(k->bufaddr + h));
  464.         k->head = h;
  465.         return r;
  466.     }
  467.     else {
  468.         if (dev == AUXDEV) {
  469.             if (has_bconmap) {
  470.                 dev = curproc->bconmap;
  471.                 h = dev-SERDEV;
  472.             } else
  473.                 h = 0;
  474.         } else
  475.             h = dev-SERDEV;
  476.  
  477.         if ((unsigned)h < btty_max || dev == 3) {
  478.             if (has_bconmap && dev != 3) {    /* help the compiler... :) */
  479.                 long *statc;
  480.  
  481.                 while (!callout1(*(statc=&MAPTAB[dev-SERDEV].bconstat), dev))
  482.                     sleep(IO_Q, (long)&bttys[h]);
  483.                 return callout1(statc[1], dev);
  484.             }
  485.             while (!BCONSTAT(dev))
  486.                 sleep(IO_Q, (long)(dev == 3 ? &midi_btty :
  487.                                 &bttys[h]));
  488.         } else if (dev > 0) {
  489.             unsigned long tick;
  490.  
  491.             tick = *((unsigned long *)0x4baL);
  492.             while (!BCONSTAT(dev)) {
  493. /* make blocking (for longer) reads eat less CPU...
  494.  * if yield()ed > 2 seconds and still no data continue with nap
  495.  */
  496.             if ((*((unsigned long *)0x4baL) - tick) > 400)
  497.                 nap(60);
  498.             else
  499.                 yield();
  500.             }
  501.         }
  502.     }
  503.  
  504.     r = BCONIN(dev);
  505.  
  506.     return r;
  507. }
  508.  
  509. /* bconout: output a character.
  510.  * returns 0 for failure, nonzero for success
  511.  */
  512.  
  513. long ARGS_ON_STACK
  514. ubconout(dev, c)
  515. int dev, c;
  516. {
  517.     FILEPTR *f;
  518.     char outp;
  519.  
  520.     if (dev < MAX_BHANDLE) {
  521.         f = curproc->handle[boutput[dev]];
  522.         if (!f) return 0;
  523.         if (is_terminal(f)) {
  524.             return tty_putchar(f, ((long)c)&0x00ff, RAW);
  525.         }
  526.         outp = c;
  527.         return (*f->dev->write)(f, &outp, 1L);
  528.     }
  529.     else if (dev == 5) {
  530.         c &= 0x00ff;
  531.         f = curproc->handle[-1];
  532.         if (!f) return 0;
  533.         if (is_terminal(f)) {
  534.             if (c < ' ') {
  535.             /* MW hack for quoted characters */
  536.                 tty_putchar(f, (long)'\033', RAW);
  537.                 tty_putchar(f, (long)'Q', RAW);
  538.             }
  539.             return tty_putchar(f, ((long)c)&0x00ff, RAW);
  540.         }
  541.     /* note: we're assuming sizeof(int) == 2 here! */
  542.         outp = c;
  543.         return (*f->dev->write)(f, &outp, 1L);
  544.     } else
  545.         return bconout(dev, c);
  546. }
  547.  
  548. long
  549. bconout(dev, c)
  550. int dev,c;
  551. {
  552.     int statdev;
  553.     long endtime;
  554. #define curtime *((unsigned long *)0x4baL)
  555.  
  556.     if (dev == AUXDEV && has_bconmap) {
  557.         dev = curproc->bconmap;
  558.     }
  559.  
  560. /* compensate for a known BIOS bug; MIDI and IKBD are switched */
  561.     if (dev == 3) {        /* MIDI */
  562.         statdev = 4;
  563.     } else if (dev == 4) {
  564.         statdev = 3;
  565.     } else {
  566.         statdev = dev;
  567.     }
  568.  
  569. /* provide a 10 second time out for the printer */
  570.     if (!BCOSTAT(statdev)) {
  571.         if (dev != PRNDEV) {
  572.             do {
  573.     /* BUG: Speedo GDOS isn't re-entrant; so printer output to the
  574.      * serial port could cause problems
  575.      */
  576.                 yield();
  577.             } while (!BCOSTAT(statdev));
  578.         } else {
  579.             endtime = curtime + 10*200L;
  580.             do {
  581. #if 0
  582.     /* Speedo GDOS isn't re-entrant, so we can't give up CPU
  583.      * time here :-(
  584.      */
  585.                 yield();
  586. #endif
  587.             } while (!BCOSTAT(statdev) && curtime < endtime);
  588.             if ( curtime >= endtime) return 0;
  589.         }
  590.     }
  591.  
  592. /* special case: many text accelerators return a bad value from
  593.  * Bconout, so we ignore the returned value for the console
  594.  * Sigh. serptch2 and hsmodem1 also screw this up, so for now let's
  595.  * only count on it being correct for the printer.
  596.  */
  597.     if (dev == PRNDEV) {
  598. /* NOTE: if your compiler complains about the next line, then Bconout is
  599.  * improperly declared in your osbind.h header file. it should be returning
  600.  * a long value; some libraries incorrectly have Bconout returning void
  601.  * (or cast the returned value to void)
  602.  */
  603.         return BCONOUT(dev,c);
  604.     } else {
  605.         (void)BCONOUT(dev, c);
  606.         return 1;
  607.     }
  608. }
  609.  
  610. /* rwabs: various disk stuff */
  611.  
  612. long ARGS_ON_STACK
  613. rwabs(rwflag, buffer, number, recno, dev, lrecno)
  614. int rwflag, number, recno, dev;
  615. void *buffer;
  616. long lrecno;
  617. {
  618.     long r;
  619.     extern PROC *dlockproc[];    /* in dosdir.c */
  620.     extern int aliasdrv[];        /* in filesys.c */
  621.  
  622.     /* jr: inspect bit 3 of rwflag!!! */
  623.     
  624.     if (!(rwflag & 8) && dev >= 0 && dev < NUM_DRIVES) {
  625.         if (aliasdrv[dev]) {
  626.             dev = aliasdrv[dev] - 1;
  627.         }
  628.         if (dlockproc[dev] && dlockproc[dev] != curproc) {
  629.             DEBUG(("Rwabs: device %c is locked", dev+'A'));
  630.             return ELOCKED;
  631.         }
  632.     }
  633.  
  634. #if 0    /* commented out so that loadable file systems work :-( */
  635. /* only the superuser can make Rwabs calls directly */
  636.  
  637.     if (curproc->in_dos || (curproc->euid == 0))
  638.     /* Note that some (most?) Rwabs device drivers don't bother saving
  639.      * registers, whereas our compiler expects politeness. So we go
  640.      * via callout(), which will save registers for us.
  641.      */
  642.         r = callout(RWABS, rwflag, buffer, number, recno, dev, lrecno);
  643.     else {
  644.         DEBUG(("Rwabs by non privileged process!"));
  645.         r = EACCDN;
  646.     }
  647. #else
  648.     r = callout(RWABS, rwflag, buffer, number, recno, dev, lrecno);
  649. #endif
  650.     return r;
  651. }
  652.  
  653. /* setexc: set exception vector */
  654.  
  655. long ARGS_ON_STACK
  656. setexc(number, vector)
  657. int number;
  658. long vector;
  659. {
  660.     long *place;
  661.     long old;
  662.     extern long save_dos, save_bios, save_xbios;    /* in main.c */
  663.     extern int no_mem_prot;                /* in main.c */
  664.  
  665.     place = (long *)(((long)number) << 2);
  666.     if (number == 0x21)                /* trap_1 */
  667.         old = save_dos;
  668.     else if (number == 0x2d)            /* trap_13 */
  669.         old = save_bios;
  670.     else if (number == 0x2e)            /* trap_14 */
  671.         old = save_xbios;
  672.     else if (number == 0x101)
  673.         old = (long)curproc->criticerr;        /* critical error vector */
  674.     else if (number == 0x102)
  675.         old = curproc->ctxt[SYSCALL].term_vec;    /* GEMDOS term vector */
  676.     else
  677.         old = *place;
  678.  
  679.     if (vector > 0) {
  680.     /* validate vector; this will cause a bus error if mem
  681.      * protection is on and the current process doesn't have
  682.      * access to the memory
  683.      */
  684.         if (*((long *)vector) == 0xDEADBEEFL)
  685.             return old;
  686.  
  687.         if (number == 0x21)
  688.             save_dos = vector;
  689.         else if (number == 0x2d)
  690.             save_bios = vector;
  691.         else if (number == 0x2e)
  692.             save_xbios = vector;
  693.         else if (number == 0x102)
  694.             curproc->ctxt[SYSCALL].term_vec = vector;
  695.         else if (number == 0x101) {
  696.             long mintcerr;
  697.  
  698.         /*
  699.          * problem: lots of TSR's look for the Setexc(0x101,...)
  700.           * that the AES does at startup time; so we have
  701.          * to pass it along.
  702.          */
  703.             mintcerr = (long) Setexc(0x101, (void *)vector);
  704.             curproc->criticerr = (long ARGS_ON_STACK (*) P_((long))) *place;
  705.             *place = mintcerr;
  706.         }
  707.         else {
  708.             if (!no_mem_prot) {
  709.             /*
  710.              * if memory protection is on, the vector should be
  711.              * pointing at supervisor or global memory
  712.              */
  713.                 MEMREGION *r;
  714.  
  715.                 r = addr2region(vector);
  716.                 if (r && get_prot_mode(r) == PROT_P) {
  717.                 DEBUG(("Changing protection to Supervisor because of Setexc"));
  718.                 mark_region(r, PROT_S);
  719.                 }
  720.             }
  721.         /* We would do just *place = vector except that
  722.          * someone else might be intercepting Setexc looking
  723.          * for something in particular...
  724.          */
  725.             old = (long) Setexc(number, (void *)vector);
  726.         }
  727.     }
  728.  
  729.     TRACE(("Setexc %d, %lx -> %lx", number, vector, old));
  730.     return old;
  731. }
  732.  
  733. /* tickcal: return milliseconds per system clock tick */
  734.  
  735. long ARGS_ON_STACK
  736. tickcal()
  737. {
  738.     return (long) (*( (unsigned *) 0x0442L ));
  739. }
  740.  
  741. /* getbpb: get BIOS parameter block */
  742.  
  743. long ARGS_ON_STACK
  744. getbpb(dev)
  745. int dev;
  746. {
  747.     long r;
  748.  
  749. /* we can't trust the Getbpb routine to accurately save all registers,
  750.  * so we do it ourselves
  751.  */
  752.     r = callout1(GETBPB, dev);
  753. /* 
  754.  * There is a bug in the  TOS  disk handling routines (well several actually).
  755.  * If the directory size of Getbpb() is returned as zero then the drive 'dies'
  756.  * and wont read any new disks even with the 'ESC' enforced disk change . This
  757.  * is present even in TOS 1.6 (not sure about 1.62 though). This small routine
  758.  * changes the dir size to '1' if it is zero . It may make some non-TOS disks
  759.  * look a bit weird but that's better than killing the drive .
  760.  */
  761.     if (r) {
  762.         if ( ((short *)r)[3] == 0)    /* 0 directory size? */
  763.             ((short *)r)[3] = 1;
  764.  
  765.         /* jr: save cluster size in area */
  766.         if (dev >= 0 && dev < 32)
  767.             clsizb[dev] = ((unsigned short *)r)[2];
  768.     }
  769.     return r;
  770. }
  771.  
  772. /* bcostat: return output device status */
  773.  
  774. /* WARNING: syscall.spp assumes that ubcostat never
  775.  * blocks
  776.  */
  777. long ARGS_ON_STACK
  778. ubcostat(dev)
  779. int dev;
  780. {
  781.     FILEPTR *f;
  782.  
  783. /* the BIOS switches MIDI (3) and IKBD (4) (a bug, but it can't be corrected) */
  784.     if (dev == 4) {        /* really the MIDI port */
  785.         f = curproc->handle[boutput[3]];
  786.         return file_outstat(f) ? -1 : 0;
  787.     }
  788.     if (dev == 3)
  789.         return BCOSTAT(dev);
  790.  
  791.     if (dev < MAX_BHANDLE) {
  792.         f = curproc->handle[boutput[dev]];
  793.         return file_outstat(f) ? -1 : 0;
  794.     } else
  795.         return bcostat(dev);
  796. }
  797.  
  798. long
  799. bcostat(dev)
  800. int dev;
  801. {
  802.  
  803.     if (dev == CONSDEV) {
  804.         return -1;
  805.     }
  806.     else if (dev == AUXDEV && has_bconmap) {
  807.         dev = curproc->bconmap;
  808.     }
  809. /* compensate here for the BIOS bug, so that the MIDI and IKBD files work
  810.  * correctly
  811.  */
  812.     else if (dev == 3) dev = 4;
  813.     else if (dev == 4) dev = 3;
  814.  
  815.     return BCOSTAT(dev);
  816. }
  817.  
  818. /* mediach: check for media change */
  819.  
  820. long ARGS_ON_STACK
  821. mediach(dev)
  822. int dev;
  823. {
  824.     long r;
  825.  
  826.     r = callout1(MEDIACH, dev);
  827.     return r;
  828. }
  829.  
  830. /* drvmap: return drives connected to system */
  831.  
  832. long ARGS_ON_STACK
  833. drvmap()
  834. {
  835.     return *( (long *)0x4c2L );
  836. }
  837.  
  838. /* kbshift: return (and possibly change) keyboard shift key status */
  839. /* WARNING: syscall.spp assumes that kbshift never blocks, and never
  840.  * calls any underlying TOS functions
  841.  */
  842. long ARGS_ON_STACK
  843. kbshift(mode)
  844. int mode;
  845. {
  846.     int oldshft;
  847.  
  848.     oldshft = *((unsigned char *)kbshft);
  849.     if (mode >= 0)
  850.         *kbshft = mode;
  851.     return oldshft;
  852. }
  853.  
  854.  
  855. /* special Bconout buffering code:
  856.  * Because system call overhead is so high, programs that do output
  857.  * with Bconout suffer in performance. To compensate for this,
  858.  * Bconout is special-cased in syscall.s, and if possible characters
  859.  * are placed in the 256 byte bconbuf buffer. This buffer is flushed
  860.  * when any system call other than Bconout happens, or when a context
  861.  * switch occurs.
  862.  */
  863.  
  864. short bconbsiz;            /* number of characters in buffer */
  865. unsigned char bconbuf[256];    /* buffer contents */
  866. short bconbdev;            /* BIOS device for which the buffer is valid */
  867.                 /* (-1 means no buffering is active) */
  868.  
  869. /*
  870.  * flush pending BIOS output. Return 0 if some bytes were not successfully
  871.  * written, non-zero otherwise (just like bconout)
  872.  */
  873.  
  874. long ARGS_ON_STACK
  875. bflush()        /* flush bios output */
  876. {
  877.     long ret, bsiz;
  878.     unsigned char *s;
  879.     FILEPTR *f;
  880.     short dev;
  881.     short statdev;
  882.     long lbconbuf[256];
  883.  
  884.     if ((dev = bconbdev) < 0) return 0;
  885.  
  886. /*
  887.  * Here we lock the BIOS buffering mechanism by setting bconbdev to -1
  888.  * This is necessary because if two or more programs try to do
  889.  * buffered BIOS output at the same time, they can get seriously
  890.  * mixed up. We unlock by setting bconbdev to 0.
  891.  *
  892.  * NOTE: some code (e.g. in sleep()) checks for bconbsiz != 0 in
  893.  * order to see if we need to do a bflush; if one is already in
  894.  * progress, it's pointless to do this, so we save a bit of
  895.  * time by setting bconbsiz to 0 here.
  896.  */
  897.     bconbdev = -1;
  898.     bsiz = bconbsiz;
  899.     if (bsiz == 0) return 0;
  900.     bconbsiz = 0;
  901.  
  902. /* BIOS handles 0..MAX_BHANDLE-1 are aliases for special GEMDOS files */
  903.     if (dev < MAX_BHANDLE || dev == 5) {
  904.         if (dev == 5)
  905.             f = curproc->handle[-1];
  906.         else
  907.             f = curproc->handle[boutput[dev]];
  908.  
  909.         if (!f) {
  910.             bconbdev = 0;
  911.             return 0;
  912.         }
  913.         if (is_terminal(f)) {
  914.             int oldflags = f->flags;
  915.  
  916.             s = bconbuf;
  917. /* turn off NDELAY for this write... */
  918.             f->flags &= ~O_NDELAY;
  919.             if (dev == 5) {
  920.                 while (bsiz-- > 0) {
  921.                 if (*s < ' ') {
  922.             /* use ESC-Q to quote control character */
  923.                     (void)tty_putchar(f, (long)'\033',
  924.                                 RAW);
  925.                     (void)tty_putchar(f, (long)'Q',
  926.                                 RAW);
  927.                 }
  928.                 (void) tty_putchar(f, (long)*s++, RAW);
  929.                 }
  930.             } else {
  931.                 long *where, nbytes;
  932. #if 1
  933.                 extern FILESYS bios_filesys;
  934.  
  935.                 /* see if we can do fast RAW byte IO thru the device driver... */
  936.                 if ((f->fc.fs != &bios_filesys ||
  937.                     (bsiz > 1 &&
  938.                      ((struct bios_file *)f->fc.index)->drvsize >
  939.                         offsetof (DEVDRV, writeb))) && f->dev->writeb) {
  940.                     struct tty *tty = (struct tty *)f->devinfo;
  941.  
  942.                 tty_checkttou (f, tty);
  943.                 tty->state &= ~TS_COOKED;
  944.                 if ((ret = (*f->dev->writeb)(f, (char *)s, bsiz)) != EUNDEV) {
  945.                     f->flags = oldflags;
  946.                     bconbdev = 0;
  947.                     return ret;
  948.                 }
  949.                 }
  950. #endif
  951. /* the tty_putchar should set up terminal modes correctly */
  952.                 (void) tty_putchar(f, (long)*s++, RAW);
  953.                 where = lbconbuf;
  954.                 nbytes = 0;
  955.                 while (--bsiz > 0) {
  956.                 *where++ = *s++; nbytes+=4;
  957.                 }
  958.                 if (nbytes)
  959.                 (*f->dev->write)(f, (char *)lbconbuf, nbytes);
  960.             }
  961.             ret = -1;
  962.             f->flags = oldflags;
  963.         } else {
  964.             ret = (*f->dev->write)(f, (char *)bconbuf, bsiz);
  965.         }
  966.         bconbdev = 0;
  967.         return ret;
  968.     }
  969.  
  970. /* Otherwise, we have a real BIOS device */
  971.  
  972.     if (dev == AUXDEV && has_bconmap) {
  973.         dev = curproc->bconmap;
  974.         statdev = dev;
  975.     }
  976.     if ((ret = iwrite (dev, bconbuf, bsiz, 0, 0)) != EUNDEV) {
  977.         bconbdev = 0;
  978.         return ret;
  979.     } else if (dev == 3) {        /* MIDI */
  980.     /* compensate for a known BIOS bug; MIDI and IKBD are switched */
  981.         statdev = 4;
  982.     } else if (dev == 4) {
  983.         statdev = 3;
  984.     } else
  985.         statdev = dev;
  986.         
  987.     s = bconbuf;
  988.     while (bsiz-- > 0) {
  989.         while (!BCOSTAT(statdev)) yield();
  990.         (void)BCONOUT(dev,*s);
  991.         s++;
  992.     }
  993.     bconbdev = 0;
  994.     return 1L;
  995. }
  996.  
  997. /* initialize bios table */
  998.  
  999. #define BIOS_MAX 0x20
  1000.  
  1001. Func bios_tab[BIOS_MAX] = {
  1002.     getmpb,
  1003.     ubconstat,
  1004.     ubconin,
  1005.     ubconout,
  1006.  
  1007.     rwabs,
  1008.     setexc,
  1009.     tickcal,
  1010.     getbpb,
  1011.  
  1012.     ubcostat,
  1013.     mediach,
  1014.     drvmap,
  1015.     kbshift,
  1016.  
  1017.     0, 0, 0, 0,
  1018.     0, 0, 0, 0, 0, 0, 0, 0,
  1019.     0, 0, 0, 0, 0, 0, 0, 0
  1020. };
  1021.  
  1022. short bios_max = BIOS_MAX;
  1023.  
  1024. /*
  1025.  * BIOS initialization routine: gets keyboard buffer pointers, for the
  1026.  * interrupt routine below
  1027.  */
  1028.  
  1029. void
  1030. init_bios()
  1031. {
  1032.     keyrec = (IOREC_T *)Iorec(1);
  1033. }
  1034.  
  1035. /*
  1036.  * do_bconin: try to do a bconin function quickly, without
  1037.  * blocking. If we can't do it without blocking, we return
  1038.  * 0x0123dead and the calling trap #13 code falls through
  1039.  * to the normal bconin stuff. We can't block here because
  1040.  * the trap #13 code hasn't yet saved registers or other
  1041.  * context bits, so sleep() wouldn't work properly.
  1042.  */
  1043.  
  1044. #define WOULDBLOCK 0x0123deadL
  1045.  
  1046. /* WARNING: syscall.spp assumes that do_bconin never blocks */
  1047.  
  1048. long ARGS_ON_STACK
  1049. do_bconin(dev)
  1050.     int dev;
  1051. {
  1052.     FILEPTR *f;
  1053.     long r, nread;
  1054.     unsigned char c;
  1055.  
  1056.     if (dev < MAX_BHANDLE) {
  1057.         f = curproc->handle[binput[dev]];
  1058.         if (!f) return 0;
  1059.         nread = 0;
  1060.         (void)(*f->dev->ioctl)(f, FIONREAD, &nread);
  1061.         if (!nread) return WOULDBLOCK;    /* data not ready */
  1062.         if (is_terminal(f))
  1063.             r = tty_getchar(f, RAW);
  1064.         else {
  1065.             r = (*f->dev->read)(f, (char *)&c, 1L);
  1066.             r = (r == 1) ? c : MiNTEOF;
  1067.         }
  1068.     } else {
  1069.         if (!bconstat(dev))
  1070.             r = WOULDBLOCK;
  1071.         else
  1072.             r = bconin(dev);
  1073.     }
  1074.     return r;
  1075. }
  1076.  
  1077. /*
  1078.  * routine for checking keyboard (called by sleep() on any context
  1079.  * switch where a keyboard event occured). returns 1 if a special
  1080.  * control character was eaten, 0 if not
  1081.  */
  1082.  
  1083. int
  1084. checkkeys()
  1085. {
  1086.     char scan, ch;
  1087.     short shift;
  1088.     int sig, ret;
  1089.     struct tty *tty = &con_tty;
  1090.     extern char mshift;        /* for mouse -- see biosfs.c */
  1091.     static short oldktail = 0;
  1092.  
  1093.     ret = 0;
  1094.     mshift = kbshift(-1);
  1095.     while (oldktail != keyrec->tail) {
  1096.  
  1097. /* BUG: we really should check the shift status _at the time the key was
  1098.  * pressed_, not now!
  1099.  */
  1100.         sig = 0;
  1101.         shift = mshift;
  1102.         oldktail += 4;
  1103.         if (oldktail >= keyrec->buflen)
  1104.             oldktail = 0;
  1105.  
  1106.         scan = (keyrec->bufaddr + oldktail)[1];
  1107. /* function key?? */
  1108.         if ( (scan >= 0x3b && scan <= 0x44) ||
  1109.              (scan >= 0x54 && scan <= 0x5d) ||
  1110.              scan == DEL || scan == UNDO) {
  1111.             if ( (shift & CTRLALT) == CTRLALT ) {
  1112.                 oldktail = keyrec->head = keyrec->tail;
  1113.                 do_func_key(scan);
  1114.                 /* do_func_key may have read some keys */
  1115.                 oldktail = keyrec->head;
  1116.                 mshift = kbshift (-1);
  1117.                 ret = 1;
  1118.                 continue;
  1119.             }
  1120.         }
  1121.  
  1122. /* check for special control keys, etc. */
  1123. /* BUG: this doesn't exactly match TOS' behavior, particularly for
  1124.  * ^S/^Q
  1125.  */
  1126.         if ((tty->state & TS_COOKED) || (shift & CTRLALT) == CTRLALT) {
  1127.             ch = (keyrec->bufaddr + keyrec->tail)[3];
  1128.             if (ch == UNDEF)
  1129.                 ;    /* do nothing */
  1130.             else if (ch == tty->tc.t_intrc)
  1131.                 sig = SIGINT;
  1132.             else if (ch == tty->tc.t_quitc)
  1133.                 sig = SIGQUIT;
  1134.             else if (ch == tty->ltc.t_suspc)
  1135.                 sig = SIGTSTP;
  1136.             else if (ch == tty->tc.t_stopc) {
  1137.                 tty->state |= TS_HOLD;
  1138.                 ret = 1;
  1139.                 keyrec->head = oldktail;
  1140.                 continue;
  1141.             }
  1142.             else if (ch == tty->tc.t_startc) {
  1143.                 tty->state &= ~TS_HOLD;
  1144.                 ret = 1;
  1145.                 keyrec->head = oldktail;
  1146.                 continue;
  1147.             }
  1148.             if (sig) {
  1149.                 tty->state &= ~TS_HOLD;
  1150.                 if (!(tty->sg.sg_flags & T_NOFLSH))
  1151.                     oldktail = keyrec->head = keyrec->tail;
  1152.                 killgroup(tty->pgrp, sig, 1);
  1153.                 ret = 1;
  1154.             }
  1155.             else if (tty->state & TS_HOLD) {
  1156.                 keyrec->head = oldktail;
  1157.                 ret = 1;
  1158.             }
  1159.         }
  1160.  
  1161.     }
  1162.  
  1163.     if (keyrec->head != keyrec->tail) {
  1164.     /* wake up any processes waiting in bconin() */
  1165.         wake(IO_Q, (long)&console_in);
  1166.     /* wake anyone that did a select() on the keyboard */
  1167.         if (tty->rsel)
  1168.             wakeselect(tty->rsel);
  1169.     }
  1170.  
  1171.     return ret;
  1172. }
  1173.  
  1174.  
  1175. /*
  1176.  * special vector stuff: we try to save as many vectors as possible,
  1177.  * just in case we need to restore them later
  1178.  *
  1179.  * BUG: this really should be integrated with the init_intr routine
  1180.  * in main.c
  1181.  */
  1182.  
  1183. #define A(x) ((long *)(long)(x))
  1184. #define L(x) (long)(x)
  1185.  
  1186. struct vectab {
  1187.     long *addr;
  1188.     long def_value;
  1189. } VEC[] = {
  1190. {A(0x28), 0},    /* Line A */
  1191. {A(0x2c), 0},    /* Line F */
  1192. {A(0x60), 0},    /* spurious interrupt */
  1193. {A(0x64), 0},      /* level 1 interrupt */
  1194. {A(0x68), 0},    /* level 2 interrupt */
  1195. {A(0x6c), 0},    /* level 3 interrupt */
  1196. {A(0x70), 0},    /* level 4 interrupt */
  1197. {A(0x74), 0},    /* level 5 interrupt */
  1198. {A(0x78), 0},    /* level 6 interrupt */
  1199. {A(0x7c), 0},    /* level 7 interrupt */
  1200. {A(0x100), 0},    /* various MFP interrupts */
  1201. {A(0x104), 0},
  1202. {A(0x108), 0},
  1203. {A(0x10c), 0},
  1204. {A(0x110), 0},
  1205. {A(0x114), 0},
  1206. {A(0x118), 0},
  1207. {A(0x11c), 0},
  1208. {A(0x120), 0},
  1209. {A(0x124), 0},
  1210. {A(0x128), 0},
  1211. {A(0x12c), 0},
  1212. {A(0x130), 0},
  1213. {A(0x134), 0},
  1214. {A(0x138), 0},
  1215. {A(0x13c), 0},
  1216. {A(0x400), 0},    /* etv_timer */
  1217. {A(0x4f6), 0},  /* shell_p */
  1218.  
  1219. {A(0), 0}    /* special tag indicating end of list */
  1220. };
  1221.  
  1222. void
  1223. init_vectors() 
  1224. {
  1225.     struct vectab *v;
  1226.  
  1227.     for (v = VEC; v->addr; v++) {
  1228.         v->def_value = *(v->addr);
  1229.     } 
  1230. }
  1231.  
  1232. #if 0    /* bad code */
  1233.  
  1234. /* unhook a vector; if possible, do this with XBRA, but
  1235.  * if that isn't possible force the vector to have the
  1236.  * same value it had when MiNT started
  1237.  */
  1238.  
  1239. static void
  1240. unhook(v, where)
  1241.     struct vectab *v;
  1242.     long where;
  1243. {
  1244.     xbra_vec *xbra;
  1245.     long newval;
  1246.     int cookie;
  1247.  
  1248. /* to check for XBRA, we need access to the memory where the
  1249.  * vector is
  1250.  */
  1251.     cookie = prot_temp(where - 12, 16L, -1);
  1252.  
  1253.     if (cookie == 0)
  1254.         newval = v->def_value;
  1255.     else {
  1256.         xbra = (xbra_vec *)(where - 12);
  1257.         if (xbra->xbra_magic == XBRA_MAGIC) {
  1258.             newval = (long)xbra->next;
  1259.         } else {
  1260.             newval = v->def_value;
  1261.         }
  1262.     }
  1263.     *(v->addr) = newval;
  1264.  
  1265.     (void)prot_temp(where - 12, 16L, cookie);
  1266. }
  1267. #endif
  1268.  
  1269. /*
  1270.  * unlink_vectors(start, end): any of the "normal" system vectors
  1271.  * pointing into a freed memory region must be reset to their
  1272.  * default values, or else we'll get a memory protection violation
  1273.  * next time the vector gets called
  1274.  */
  1275.  
  1276. void
  1277. unlink_vectors(start, end)
  1278.     long start, end;
  1279. {
  1280. #if 0    /* this code is hosed somewhere */
  1281.  
  1282.     struct vectab *v;
  1283.     long where, *p;
  1284.     int i;
  1285.  
  1286. /* first, unhook any VBL handlers */
  1287.     i = *((short *)0x454L);    /* i = nvbls */
  1288.     p = *((long **)0x456L);    /* p = _vblqueue */
  1289.     while (i-- > 0) {
  1290.         where = *p;
  1291.         if (where >= start && where < end)
  1292.             *p = 0;
  1293.         p++;
  1294.     }
  1295.  
  1296. /* next, unhook various random vectors */
  1297.     for (v = VEC; v->addr; v++) {
  1298.         where = *(v->addr);
  1299.         if (where >= start && where < end) {
  1300.             unhook(v, where);
  1301.         }
  1302.     }
  1303. #else
  1304.     UNUSED(start); UNUSED(end);
  1305. #endif
  1306. }
  1307.  
  1308.